home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Display Manager / Display Manager Sample Code / Play Video Sample / RequestVideo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-06-24  |  27.3 KB  |  739 lines  |  [TEXT/CWIE]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    MacOS™ Sample Code
  4. #    
  5. #    Written by: Eric Anderson
  6. #    Additional Input: David Lawrence
  7. #     email: eric3@apple.com
  8. #
  9. #    Display Manager sample code
  10. #
  11. #    RequestVideo
  12. #
  13. #    RequestVideo.c    -    C Code
  14. #
  15. #    Copyright © 1995 Apple Computer, Inc.
  16. #    All rights reserved.
  17. #
  18. #    1/28/97        ewa        Updated source for Metrowerks CodeWarrior 11
  19. #    6/27/96        dal        RVRequestVideoSetting() no longer requires Slot Manager DM 2.0 can be used.
  20. #    6/27/96        dal        Added check for Display Library before making DM 2.0 calls.
  21. #    5/31/95        ewa        Added RVGetCurrentVideoSetting and RVConfirmVideoRequest routines
  22. #                        to make it easy to revert back to where you came from and to give
  23. #                        the user a chance to confirm the new setting if the new mode was
  24. #                        valid (ie: the card supports it) but not safe (the monitor may not).
  25. #    5/24/95        ewa        Give the kAllValidModesBit requestFlags option for safe only or all
  26. #                        valid resolution timings.
  27. #
  28. #
  29. #
  30. #    Components:    PlayVideo.c            
  31. #                RequestVideo.c        
  32. #                RequestVideo.h        
  33. #                RequestVideo.rsrc        
  34. #
  35. #    RequestVideo demonstrates the usage of the Display Manager introduced
  36. #    with the PowerMacs and integrated into the system under System 7.5. With
  37. #    the RequestVideo sample code library, developers will be able to explore
  38. #    the Display Manager API by changing bit depth and screen resolution on
  39. #    multisync displays on built-in, NuBus, and PCI based video. Display Manager 1.0
  40. #    is built into the Systems included with the first PowerMacs up through System 7.5.
  41. #    Display Manager 2.0 is included with the release of the new PCI based PowerMacs,
  42. #    and will be included in post 7.5 System Software releases. 
  43. #    
  44. #    It is a good idea to reset the screen(s) to the original setting before exit
  45. #    since the call to RVSetVideoAsScreenPrefs() may not do the right thing under
  46. #    Display Manager 1.0 with certain video drivers.
  47. #
  48. #    For information on the use of this sample code, please the documentation in the Read Me file
  49. #
  50. ------------------------------------------------------------------------------*/
  51.  
  52. #include "RequestVideo.h"
  53.  
  54. // Internal includes
  55. #include <Dialogs.h>
  56. #include <ROMDefs.h>
  57. #include <Devices.h>
  58. #include <Errors.h>
  59. #include <Gestalt.h>
  60. #include <Memory.h>
  61. #include <Palettes.h>
  62. #include <Slots.h>
  63. #include <Displays.h>
  64. #include <ConditionalMacros.h>    //DL
  65. #include <CodeFragments.h>    //DL
  66.  
  67. #if 0
  68. //#include <StdIO.h>
  69. //#include <stdlib.h>
  70. #else
  71. #define abs(x) ( ( (x) < 0 ) ? -(x) : (x) )
  72. #endif
  73.  
  74. //--------------------------------------------------------------
  75. //
  76. // Internal defines, structs, typedefs, and routine declarations
  77. //
  78. //--------------------------------------------------------------
  79. #define        KMonoDev            0                        // false (handy definitions for gdDevType settings)
  80. #define        kColorDev            1                        // true
  81. #define        char_Enter            0x03                    // for our filter proc
  82. #define        char_Return            0x0D                    //
  83. #define        iRevertItem            1                        // User buttons
  84. #define        iConfirmItem        2                        //
  85. #define        kSecondsToConfirm    8                        // seconds before confirm dialog is taken down
  86. #define        rConfirmSwtchAlrt    2735                    // ID of alert dialog
  87.  
  88. struct DepthInfo {
  89.     VDSwitchInfoRec            depthSwitchInfo;            // This is the switch mode to choose this timing/depth
  90.     VPBlock                    depthVPBlock;                // VPBlock (including size, depth and format)
  91. };
  92. typedef struct DepthInfo DepthInfo;
  93.  
  94. struct ListIteratorDataRec {
  95.     VDTimingInfoRec            displayModeTimingInfo;        // Contains timing flags and such
  96.     unsigned long            depthBlockCount;            // How many depths available for a particular timing
  97.     DepthInfo                *depthBlocks;                // Array of DepthInfo
  98. };
  99. typedef struct ListIteratorDataRec ListIteratorDataRec;
  100.  
  101. void GetRequestTheDM1Way (        VideoRequestRecPtr requestRecPtr,
  102.                                 GDHandle walkDevice);
  103.  
  104. void GetRequestTheDM2Way (        VideoRequestRecPtr requestRecPtr,
  105.                                 GDHandle walkDevice,
  106.                                 DMDisplayModeListIteratorUPP myModeIteratorProc,
  107.                                 DMListIndexType theDisplayModeCount,
  108.                                 DMListType *theDisplayModeList);
  109.  
  110. pascal void ModeListIterator (    void *userData,
  111.                                 DMListIndexType itemIndex,
  112.                                 DMDisplayModeListEntryPtr displaymodeInfo);
  113.  
  114. Boolean FindBestMatch (            VideoRequestRecPtr requestRecPtr,
  115.                                 short bitDepth,
  116.                                 unsigned long horizontal,
  117.                                 unsigned long vertical);
  118.  
  119. void GravitateMonitors (void);
  120.  
  121. pascal Boolean ConfirmAlertFilter (DialogRef dlg, EventRecord *evt, short *itemHit);
  122.  
  123. //--------------------------------------------------------------
  124. //
  125. // Implementation of sample code
  126. //
  127. //--------------------------------------------------------------
  128. OSErr RVSetVideoRequest (VideoRequestRecPtr requestRecPtr)
  129. {
  130.     GDHandle        aMonitor;
  131.     Boolean            displayMgrPresent;
  132.     unsigned long    displayMgrVersion;
  133.     OSErr            err;
  134.     Boolean            isColor;
  135.     long            value = 0;
  136.  
  137.     Gestalt(gestaltDisplayMgrVers, (long*)&displayMgrVersion);
  138.     Gestalt(gestaltDisplayMgrAttr,&value);
  139.     displayMgrPresent=value&(1<<gestaltDisplayMgrPresent);
  140.     if (displayMgrPresent)
  141.     {
  142.         if (requestRecPtr->displayMode && requestRecPtr->depthMode)
  143.         {
  144.             if (requestRecPtr->availBitDepth == 1)    // Based on avail bit depth, 
  145.                 isColor = KMonoDev;                    // set the device to a mono device, or
  146.             else isColor = kColorDev;                // set the device to a color device
  147.             SetDeviceAttribute(requestRecPtr->screenDevice,gdDevType,isColor);        
  148.             
  149.             // see how many monitors we have, aMonitor will be nil if we have only one.
  150.             aMonitor = DMGetFirstScreenDevice (dmOnlyActiveDisplays);            // get the first guy
  151.             aMonitor = DMGetNextScreenDevice ( aMonitor, dmOnlyActiveDisplays );    // get the next guy
  152.             
  153.             if (nil == aMonitor || displayMgrVersion >= 0x00020000)
  154.             {
  155.                 // only call DMSetDisplayMode if we have one monitor or DM2.0 is installed
  156.                 // since DM1.0 does not automatically gravitate monitors and our gravitate code
  157.                 // is not implemented.
  158.                 err = DMSetDisplayMode(    requestRecPtr->screenDevice,    // GDevice
  159.                         requestRecPtr->displayMode,                        // DM1.0 uses this
  160.                         &requestRecPtr->depthMode,                        // DM1.0 uses this
  161.                         (unsigned long) &(requestRecPtr->switchInfo),    // DM2.0 uses this rather than displayMode/depthMode combo
  162.                         nil);
  163.                 if (noErr == err)
  164.                 {
  165.                     // Do the monitor gravitate here if we are using a version less than DM2.0
  166.                     if (displayMgrVersion < 0x00020000)
  167.                         GravitateMonitors ();
  168.                 }
  169.                 else if (kDMDriverNotDisplayMgrAwareErr == err)
  170.                 {
  171.                     // DM not supported by driver, so all we can do is set the bit depth
  172.                     err = SetDepth (requestRecPtr->screenDevice, requestRecPtr->depthMode, gdDevType, isColor);
  173.                 }
  174.             }
  175.             else
  176.             {
  177.                 // we have more than one monitor and DM1.0 is installed, so all we can do is set the bit depth
  178.                 err = SetDepth (requestRecPtr->screenDevice, requestRecPtr->depthMode, gdDevType, isColor);
  179.             }
  180.             
  181.             return (err);    // we did try to set the request
  182.         }
  183.     }
  184.     return (-1);    // return a generic error
  185. }
  186.  
  187. // This extern should be removed once this function is formally defined in Displays.h
  188. extern pascal OSErr DMUseScreenPrefs(Boolean usePrefs, Handle displayState)
  189.  THREEWORDINLINE(0x303C, 0x03EC, 0xABEB);
  190.  
  191. OSErr RVSetVideoAsScreenPrefs (void)
  192. {
  193.     Handle        displaystate;
  194.     Boolean        displayMgrPresent;
  195.     long        value = 0;
  196.  
  197.     Gestalt(gestaltDisplayMgrAttr,&value);
  198.     displayMgrPresent=value&(1<<gestaltDisplayMgrPresent);
  199.     if (displayMgrPresent)
  200.     {
  201.         DMBeginConfigureDisplays (&displaystate);    // Tell the world it is about to change
  202.         DMUseScreenPrefs (true, displaystate);        // Make the change
  203.         DMEndConfigureDisplays (displaystate);        // Tell the world the change is over
  204.         
  205.         return (noErr);    // we (maybe) set the world back to a known setting
  206.     }
  207.     return (-1);    // return a generic error
  208. }
  209.  
  210. OSErr RVGetCurrentVideoSetting (VideoRequestRecPtr requestRecPtr)
  211. {
  212.     unsigned long        displayMgrVersion;
  213.     OSErr                error = paramErr;
  214.     CntrlParam            pBlock;
  215.     VDSwitchInfoRec        switchInfo;
  216.     AuxDCEHandle        theDCE;
  217.     VDSwitchInfoRec        videoMode;        
  218.  
  219.     requestRecPtr->availBitDepth            = 0;    // init to default - you can do it if it is important to you
  220.     requestRecPtr->availHorizontal            = 0;
  221.     requestRecPtr->availVertical            = 0;
  222.     requestRecPtr->availFlags                = 0;
  223.     requestRecPtr->displayMode                = -1; 
  224.     requestRecPtr->depthMode                = -1;
  225.     requestRecPtr->switchInfo.csMode        = 0;
  226.     requestRecPtr->switchInfo.csData        = 0;
  227.     requestRecPtr->switchInfo.csPage        = 0;
  228.     requestRecPtr->switchInfo.csBaseAddr    = 0;
  229.     requestRecPtr->switchInfo.csReserved    = 0;
  230.     
  231.     Gestalt(gestaltDisplayMgrVers, (long*)&displayMgrVersion);
  232.     if (requestRecPtr->screenDevice)
  233.     {
  234. //DL -    must also make sure that Display Library is installed, otherwise
  235. //        calling DMGetDisplayMode() will branch to nil.
  236. //DL        if (displayMgrVersion >= 0x00020000)
  237. #if GENERATINGCFM
  238.         if (displayMgrVersion >= 0x00020000 && (Ptr) DMGetDisplayMode != (Ptr) kUnresolvedCFragSymbolAddress)
  239. #else
  240.         if (displayMgrVersion >= 0x00020000)
  241. #endif
  242.         {    // get the info the DM 2.0 way
  243.             error = DMGetDisplayMode(requestRecPtr->screenDevice, &switchInfo);
  244.             if (noErr == error)
  245.             {
  246.                 requestRecPtr->depthMode            = switchInfo.csMode;
  247.                 requestRecPtr->displayMode            = switchInfo.csData; 
  248.                 requestRecPtr->switchInfo.csMode    = switchInfo.csMode;
  249.                 requestRecPtr->switchInfo.csData    = switchInfo.csData;
  250.             }
  251.             return (error);    // we (maybe) set the world back to a known setting
  252.         }
  253.         else
  254.         {    // get the info the DM 1.0 way
  255.             videoMode.csMode = -1;        // init to bogus value
  256.             videoMode.csData = -1;        // init to bogus value            
  257.             pBlock.ioNamePtr = nil;
  258.             pBlock.ioCRefNum = (*(requestRecPtr->screenDevice))->gdRefNum;
  259.             pBlock.csCode = cscGetCurMode;
  260.             *(Ptr *)&pBlock.csParam[0] = (Ptr)&videoMode;
  261.                 
  262.             error = PBStatusSync((ParmBlkPtr )&pBlock);    // ask the driver first....since we trust it the most
  263.                 
  264.             if ( noErr == error && ((-1 == videoMode.csMode) || (-1 == videoMode.csData)) )
  265.                 error = statusErr;
  266.             
  267.             if (noErr != error)    // if the driver has no clue fill it videoMode by hand as a last resort
  268.             {    
  269.                 theDCE = (AuxDCEHandle)GetDCtlEntry((*(requestRecPtr->screenDevice))->gdRefNum);
  270.                 
  271.                 if( theDCE )
  272.                 {
  273.                     videoMode.csData = (unsigned char)(*theDCE)->dCtlSlotId; 
  274.                     videoMode.csMode = (*(requestRecPtr->screenDevice))->gdMode;
  275.                     error = noErr;
  276.                 }
  277.             }
  278.             if (noErr == error)    // Set our data
  279.             {
  280.                 requestRecPtr->displayMode            = videoMode.csData; 
  281.                 requestRecPtr->depthMode            = videoMode.csMode;
  282.                 requestRecPtr->switchInfo.csMode    = videoMode.csMode;
  283.                 requestRecPtr->switchInfo.csData    = videoMode.csData;
  284.             }
  285.             return (error);    // we (maybe) set the world back to a known setting
  286.         }
  287.     }
  288.     return (-1);
  289. }
  290.  
  291. pascal Boolean ConfirmAlertFilter(DialogRef theDialog, EventRecord *theEvent, short *itemHit)
  292. {
  293.     char charCode;
  294.     Boolean enterORreturn;
  295.     Boolean returnValue = false;
  296.     WindowRef dialogWindow = GetDialogWindow(theDialog);    //DL
  297.  
  298.     if (0 == GetWRefCon(dialogWindow))
  299.         SetWRefCon (dialogWindow,TickCount());
  300.     else
  301.     {
  302.         if (GetWRefCon(dialogWindow) + kSecondsToConfirm * 60 < TickCount())
  303.         {
  304.             returnValue = true;
  305.             theEvent->what = nullEvent;
  306.             *itemHit = 1;
  307.         }
  308.         else
  309.         {
  310.             if (theEvent->what == keyDown)
  311.             {
  312.                 charCode = (char)theEvent->message & charCodeMask;
  313.                 enterORreturn = (charCode == (char)char_Return) || (charCode == (char)char_Enter);
  314.                 if (enterORreturn)
  315.                 {
  316.                     theEvent->what = nullEvent;
  317.                     returnValue = true;
  318.                     *itemHit = iRevertItem;
  319.                     if (enterORreturn && (0 != (theEvent->modifiers & optionKey)))
  320.                     {
  321.                         *itemHit = iConfirmItem;
  322.                     }
  323.                 }
  324.             }
  325.         }
  326.     }
  327.     return (returnValue);
  328. }
  329.  
  330. OSErr RVConfirmVideoRequest (VideoRequestRecPtr requestRecPtr)
  331. {
  332.     short            alertReturn;        // Alert() return value
  333.     ModalFilterUPP    confirmFilterUPP;    // got to have us one of them new fangled UPP thingies
  334.     
  335.     if (requestRecPtr->availFlags & 1<<kModeValidNotSafeBit)
  336.     {    // new mode is valid but not safe, so ask user to confirm
  337.         SetCursor(&qd.arrow);                                        // have to show the arrow
  338.  
  339.         confirmFilterUPP = NewModalFilterProc (ConfirmAlertFilter);    // create a new modal filter proc UPP
  340.         alertReturn = Alert(rConfirmSwtchAlrt, confirmFilterUPP);    // alert the user
  341.         DisposeRoutineDescriptor (confirmFilterUPP);                // of course there is no DisposeModalFilterProc...
  342.         
  343.         if (alertReturn != iConfirmItem)
  344.             return (-1);                            // tell the caller to switch back to a known setting
  345.         else return (noErr);                        // all is well with the new setting, just leave it
  346.     }
  347.     return (noErr);                                    // the mode was safe, so do nothing
  348. }
  349.  
  350.  
  351. OSErr RVRequestVideoSetting (VideoRequestRecPtr requestRecPtr)
  352. {
  353.     Boolean                            displayMgrPresent;
  354.     short                            iCount = 0;                    // just a counter of GDevices we have seen
  355.     DMDisplayModeListIteratorUPP    myModeIteratorProc = nil;    // for DM2.0 searches
  356.     SpBlock                            spBlock;
  357.     Boolean                            suppliedGDevice;    
  358.     DisplayIDType                    theDisplayID;                // for DM2.0 searches
  359.     DMListIndexType                    theDisplayModeCount;        // for DM2.0 searches
  360.     DMListType                        theDisplayModeList;            // for DM2.0 searches
  361.     long                            value = 0;
  362.     GDHandle                        walkDevice = nil;            // for everybody
  363. //DL START Check for the presence of DM 2.0 before calling DMNewDisplayModeList() and DMDisposeList().
  364.     OSErr                            gestaltErr;
  365.     unsigned long                    displayMgrVersion;
  366.     Boolean                         hasDM2 = false;
  367.     Boolean                         hasSlotMgr = false;
  368.     
  369.     gestaltErr = Gestalt(gestaltDisplayMgrVers, (long*)&displayMgrVersion);
  370.     if (    gestaltErr == noErr &&
  371. #if GENERATINGCFM
  372.             (Ptr) DMNewDisplayModeList != (Ptr) kUnresolvedCFragSymbolAddress &&
  373.             (Ptr) DMDisposeList != (Ptr) kUnresolvedCFragSymbolAddress &&
  374. #endif
  375.             displayMgrVersion >= 0x00020000    )
  376.     {
  377.         hasDM2 = true;
  378.     }
  379. //DL END
  380.  
  381.     Gestalt(gestaltDisplayMgrAttr,&value);
  382.     displayMgrPresent=value&(1<<gestaltDisplayMgrPresent);
  383. //DL    displayMgrPresent=displayMgrPresent && (SVersion(&spBlock)==noErr);    // need slot manager
  384.     hasSlotMgr = (SVersion(&spBlock)==noErr);    //DL
  385.     displayMgrPresent=displayMgrPresent && (hasDM2 || hasSlotMgr);    //DL - need slot manager only if using DM 1.0.
  386.     if (displayMgrPresent)
  387.     {
  388.         // init the needed data before we start
  389.         if (requestRecPtr->screenDevice)                            // user wants a specifc device?
  390.         {
  391.             walkDevice = requestRecPtr->screenDevice;
  392.             suppliedGDevice = true;
  393.         }
  394.         else
  395.         {
  396.             walkDevice = DMGetFirstScreenDevice (dmOnlyActiveDisplays);            // for everybody
  397.             suppliedGDevice = false;
  398.         }
  399.         
  400.         myModeIteratorProc = NewDMDisplayModeListIteratorProc(ModeListIterator);    // for DM2.0 searches
  401.     
  402.         // Note that we are hosed if somebody changes the gdevice list behind our backs while we are iterating....
  403.         // ...now do the loop if we can start
  404.         if( walkDevice && myModeIteratorProc) do // start the search
  405.         {
  406.             iCount++;        // GDevice we are looking at (just a counter)
  407.             if( noErr == DMGetDisplayIDByGDevice( walkDevice, &theDisplayID, false ) )    // DM1.0 does not need this, but it fits in the loop
  408.             {
  409.                 theDisplayModeCount = 0;    // for DM2.0 searches
  410. //DL                if (noErr == DMNewDisplayModeList(theDisplayID, 0, 0, &theDisplayModeCount, &theDisplayModeList) )
  411.                 if (hasDM2 && noErr == DMNewDisplayModeList(theDisplayID, 0, 0, &theDisplayModeCount, &theDisplayModeList) )
  412.                 {
  413.                     // search NuBus & PCI the new kool way through Display Manager 2.0
  414.                     GetRequestTheDM2Way (requestRecPtr, walkDevice, myModeIteratorProc, theDisplayModeCount, &theDisplayModeList);
  415.                     DMDisposeList(theDisplayModeList);    // now toss the lists for this gdevice and go on to the next one
  416.                 }
  417. //DL                else
  418.                 else if (hasSlotMgr)    //DL
  419.                 {
  420.                     // search NuBus only the old disgusting way through the slot manager
  421.                     GetRequestTheDM1Way (requestRecPtr, walkDevice);
  422.                 }
  423.             }
  424.         } while ( !suppliedGDevice && nil != (walkDevice = DMGetNextScreenDevice ( walkDevice, dmOnlyActiveDisplays )) );    // go until no more gdevices
  425.         if( myModeIteratorProc )
  426.             DisposeRoutineDescriptor(myModeIteratorProc);
  427.         return (noErr);    // we were able to get the look for a match
  428.     }
  429.     return (-1);        // return a generic error
  430. }
  431.  
  432. void GetRequestTheDM1Way (VideoRequestRecPtr requestRecPtr, GDHandle walkDevice)
  433. {
  434.     AuxDCEHandle myAuxDCEHandle;
  435.     unsigned long    depthMode;
  436.     unsigned long    displayMode;
  437.     OSErr            error;
  438.     OSErr            errorEndOfTimings;
  439.     short            height;
  440.     short            jCount = 0;
  441.     Boolean            modeOk;
  442.     SpBlock            spAuxBlock;
  443.     SpBlock            spBlock;
  444.     unsigned long    switchFlags;
  445.     VPBlock            *vpData;
  446.     short            width;
  447.  
  448.     myAuxDCEHandle = (AuxDCEHandle) GetDCtlEntry((**walkDevice).gdRefNum);    
  449.     spBlock.spSlot = (**myAuxDCEHandle).dCtlSlot;
  450.     spBlock.spID = (**myAuxDCEHandle).dCtlSlotId;
  451.     spBlock.spExtDev = (**myAuxDCEHandle).dCtlExtDev;
  452.     spBlock.spHwDev = 0;                                // we are going to get this pup
  453.     spBlock.spParamData = 1<<foneslot;                    // this slot, enabled, and it better be here.
  454.     spBlock.spTBMask = 3;                                // don't have constants for this yet
  455.     errorEndOfTimings = SGetSRsrc(&spBlock);            // get the spDrvrHW so we know the ID of this puppy. This is important
  456.                                                         // since some video cards support more than one display, and the spDrvrHW
  457.                                                         // ID can, and will, be used to differentiate them.
  458.     
  459.     if ( noErr == errorEndOfTimings )
  460.     {
  461.         // reinit the param block for the SGetTypeSRsrc loop, keep the spDrvrHW we just got
  462.         spBlock.spID = 0;                                // start at zero, 
  463.         spBlock.spTBMask = 2;                            // 0b0010 - ignore DrvrSW - why ignore the SW side? Is it not important for video?
  464.         spBlock.spParamData = (1<<fall) + (1<<foneslot) + (1<<fnext);    // 0b0111 - this slot, enabled or disabled, so we even get 640x399 on Blackbird
  465.         spBlock.spCategory=catDisplay;
  466.         spBlock.spCType=typeVideo;
  467.         errorEndOfTimings = SGetTypeSRsrc(&spBlock);    // but only on 7.0 systems, not a problem since we require DM1.0
  468.         
  469.         // now, loop through all the timings for this GDevice
  470.         if ( noErr == errorEndOfTimings ) do
  471.         {
  472.             // now, loop through all possible depth modes for this timing mode
  473.             displayMode = (unsigned char)spBlock.spID;    // "timing mode, ie:resource ref number"
  474.             for (jCount = firstVidMode; jCount<= sixthVidMode; jCount++)
  475.             {
  476.                 depthMode = jCount;        // vid mode
  477.                 error = DMCheckDisplayMode(walkDevice,displayMode,depthMode,&switchFlags,0,&modeOk);
  478.     
  479.                 // only if the mode is safe or we override it with the kAllValidModesBit request flag
  480.                 if (    noErr == error &&
  481.                         modeOk &&
  482.                         (    switchFlags & 1<<kNoSwitchConfirmBit ||
  483.                             requestRecPtr->requestFlags & 1<<kAllValidModesBit
  484.                         )
  485.                     )
  486.                 {
  487.                     // have a good displayMode/depthMode combo - now lets look inside
  488.                     spAuxBlock = spBlock;                // don't ruin the iteration spBlock!!
  489.                     spAuxBlock.spID = depthMode;        // vid mode
  490.                     error=SFindStruct(&spAuxBlock);        // get back a new spsPointer
  491.                     if (noErr == error)                    // keep going if no error…
  492.                     {
  493.                         spAuxBlock.spID = 0x01;            // mVidParams request
  494.                         error=SGetBlock (&spAuxBlock);    // use the new spPointer and get back...a NewPtr'ed spResult
  495.                         if (noErr == error)                // …keep going if no error…
  496.                         {                                // We have data! lets have a look
  497.                             vpData = (VPBlock*)spAuxBlock.spResult;
  498.                             height = vpData->vpBounds.bottom;    // left and top are usually zero
  499.                             width = vpData->vpBounds.right;
  500.                             
  501.                             if (FindBestMatch (requestRecPtr, vpData->vpPixelSize, vpData->vpBounds.right, vpData->vpBounds.bottom))
  502.                             {
  503.                                 requestRecPtr->screenDevice = walkDevice;
  504.                                 requestRecPtr->availBitDepth = vpData->vpPixelSize;
  505.                                 requestRecPtr->availHorizontal = vpData->vpBounds.right;
  506.                                 requestRecPtr->availVertical = vpData->vpBounds.bottom;
  507.                                 requestRecPtr->displayMode = displayMode;
  508.                                 requestRecPtr->depthMode = depthMode;
  509.                                 requestRecPtr->switchInfo.csMode = depthMode;                // fill in for completeness
  510.                                 requestRecPtr->switchInfo.csData = displayMode;
  511.                                 requestRecPtr->switchInfo.csPage = 0;
  512.                                 requestRecPtr->switchInfo.csBaseAddr = 0;
  513.                                 requestRecPtr->switchInfo.csReserved = 0;
  514.                                 if (switchFlags & 1<<kNoSwitchConfirmBit)
  515.                                     requestRecPtr->availFlags = 0;                            // mode safe
  516.                                 else requestRecPtr->availFlags = 1<<kModeValidNotSafeBit;    // mode valid but not safe, requires user validation of mode switch
  517.                             }
  518.  
  519.                             if (spAuxBlock.spResult) DisposePtr ((Ptr)spAuxBlock.spResult);    // toss this puppy when done
  520.                         }
  521.                     }
  522.                 }
  523.             }
  524.             // go around again, looking for timing modes for this GDevice
  525.             spBlock.spTBMask = 2;        // ignore DrvrSW
  526.             spBlock.spParamData =  (1<<fall) + (1<<foneslot) + (1<<fnext);    // next resource, this slot, whether enabled or disabled
  527.             errorEndOfTimings = SGetTypeSRsrc(&spBlock);    // and get the next timing mode
  528.         } while ( noErr == errorEndOfTimings );    // until the end of this GDevice
  529.     }
  530.  
  531. }
  532.  
  533. pascal void ModeListIterator(void *userData, DMListIndexType, DMDisplayModeListEntryPtr displaymodeInfo)
  534. {
  535.     unsigned long            depthCount;
  536.     short                    iCount;
  537.     ListIteratorDataRec        *myIterateData        = (ListIteratorDataRec*) userData;
  538.     DepthInfo                *myDepthInfo;
  539.     
  540.     // set user data in a round about way
  541.     myIterateData->displayModeTimingInfo        = *displaymodeInfo->displayModeTimingInfo;
  542.     
  543.     // now get the DMDepthInfo info into memory we own
  544.     depthCount = displaymodeInfo->displayModeDepthBlockInfo->depthBlockCount;
  545.     myDepthInfo = (DepthInfo*)NewPtrClear(depthCount * sizeof(DepthInfo));
  546.  
  547.     // set the info for the caller
  548.     myIterateData->depthBlockCount = depthCount;
  549.     myIterateData->depthBlocks = myDepthInfo;
  550.  
  551.     // and fill out all the entries
  552.     if (depthCount) for (iCount=0; iCount < depthCount; iCount++)
  553.     {
  554.         myDepthInfo[iCount].depthSwitchInfo = 
  555.             *displaymodeInfo->displayModeDepthBlockInfo->depthVPBlock[iCount].depthSwitchInfo;
  556.         myDepthInfo[iCount].depthVPBlock = 
  557.             *displaymodeInfo->displayModeDepthBlockInfo->depthVPBlock[iCount].depthVPBlock;
  558.     }
  559. }
  560.  
  561. void GetRequestTheDM2Way (    VideoRequestRecPtr requestRecPtr,
  562.                             GDHandle walkDevice,
  563.                             DMDisplayModeListIteratorUPP myModeIteratorProc,
  564.                             DMListIndexType theDisplayModeCount,
  565.                             DMListType *theDisplayModeList)
  566. {
  567.     short                    jCount;
  568.     short                    kCount;
  569.     ListIteratorDataRec        searchData;
  570.  
  571.     searchData.depthBlocks = nil;
  572.     // get the mode lists for this GDevice
  573.     for (jCount=0; jCount<theDisplayModeCount; jCount++)        // get info on all the resolution timings
  574.     {
  575.         DMGetIndexedDisplayModeFromList(*theDisplayModeList, jCount, 0, myModeIteratorProc, &searchData);
  576.         
  577.         // for all the depths for this resolution timing (mode)...
  578.         if (searchData.depthBlockCount) for (kCount = 0; kCount < searchData.depthBlockCount; kCount++)
  579.         {
  580.             // only if the mode is valid and is safe or we override it with the kAllValidModesBit request flag
  581.             if    (    searchData.displayModeTimingInfo.csTimingFlags & 1<<kModeValid && 
  582.                     (    searchData.displayModeTimingInfo.csTimingFlags & 1<<kModeSafe ||
  583.                         requestRecPtr->requestFlags & 1<<kAllValidModesBit
  584.                     )
  585.                 )
  586.             {
  587.                 if (FindBestMatch (    requestRecPtr,
  588.                                     searchData.depthBlocks[kCount].depthVPBlock.vpPixelSize,
  589.                                     searchData.depthBlocks[kCount].depthVPBlock.vpBounds.right,
  590.                                     searchData.depthBlocks[kCount].depthVPBlock.vpBounds.bottom))
  591.                 {
  592.                     requestRecPtr->screenDevice = walkDevice;
  593.                     requestRecPtr->availBitDepth = searchData.depthBlocks[kCount].depthVPBlock.vpPixelSize;
  594.                     requestRecPtr->availHorizontal = searchData.depthBlocks[kCount].depthVPBlock.vpBounds.right;
  595.                     requestRecPtr->availVertical = searchData.depthBlocks[kCount].depthVPBlock.vpBounds.bottom;
  596.                     
  597.                     // now set the important info for DM to set the display
  598.                     requestRecPtr->depthMode = searchData.depthBlocks[kCount].depthSwitchInfo.csMode;
  599.                     requestRecPtr->displayMode = searchData.depthBlocks[kCount].depthSwitchInfo.csData;
  600.                     requestRecPtr->switchInfo = searchData.depthBlocks[kCount].depthSwitchInfo;
  601.                     if (searchData.displayModeTimingInfo.csTimingFlags & 1<<kModeSafe)
  602.                         requestRecPtr->availFlags = 0;                            // mode safe
  603.                     else requestRecPtr->availFlags = 1<<kModeValidNotSafeBit;    // mode valid but not safe, requires user validation of mode switch
  604.     
  605.                 }
  606.             }
  607.  
  608.         }
  609.     
  610.         if (searchData.depthBlocks)
  611.         {
  612.             DisposePtr ((Ptr)searchData.depthBlocks);    // toss for this timing mode of this gdevice
  613.             searchData.depthBlocks = nil;                // init it just so we know
  614.         }
  615.     }
  616. }
  617.  
  618. Boolean FindBestMatch (VideoRequestRecPtr requestRecPtr, short bitDepth, unsigned long horizontal, unsigned long vertical)
  619. {
  620.     // •• do the big comparison ••
  621.     // first time only if    (no mode yet) and
  622.     //                        (bounds are greater/equal or kMaximizeRes not set) and
  623.     //                        (depth is less/equal or kShallowDepth not set) and
  624.     //                        (request match or kAbsoluteRequest not set)
  625.     if    (    nil == requestRecPtr->displayMode
  626.             &&
  627.             (    (horizontal >= requestRecPtr->reqHorizontal &&
  628.                 vertical >= requestRecPtr->reqVertical)
  629.                 ||                                                        
  630.                 !(requestRecPtr->requestFlags & 1<<kMaximizeResBit)    
  631.             )
  632.             &&
  633.             (    bitDepth <= requestRecPtr->reqBitDepth ||    
  634.                 !(requestRecPtr->requestFlags & 1<<kShallowDepthBit)        
  635.             )
  636.             &&
  637.             (    (horizontal == requestRecPtr->reqHorizontal &&    
  638.                 vertical == requestRecPtr->reqVertical &&
  639.                 bitDepth == requestRecPtr->reqBitDepth)
  640.                 ||
  641.                 !(requestRecPtr->requestFlags & 1<<kAbsoluteRequestBit)    
  642.             )
  643.         )
  644.         {
  645.             // go ahead and set the new values
  646.             return (true);
  647.         }
  648.     else    // can we do better than last time?
  649.     {
  650.         // if    (kBitDepthPriority set and avail not equal req) and
  651.         //        ((depth is greater avail and depth is less/equal req) or kShallowDepth not set) and
  652.         //        (avail depth less reqested and new greater avail) or
  653.         //        (request match or kAbsoluteRequest not set)
  654.         if    (    (    requestRecPtr->requestFlags & 1<<kBitDepthPriorityBit && 
  655.                     requestRecPtr->availBitDepth != requestRecPtr->reqBitDepth
  656.                 )
  657.                 &&
  658.                 (    (    bitDepth > requestRecPtr->availBitDepth &&
  659.                         bitDepth <= requestRecPtr->reqBitDepth
  660.                     )
  661.                     ||
  662.                     !(requestRecPtr->requestFlags & 1<<kShallowDepthBit)    
  663.                 )
  664.                 &&
  665.                 (    requestRecPtr->availBitDepth < requestRecPtr->reqBitDepth &&
  666.                     bitDepth > requestRecPtr->availBitDepth    
  667.                 )
  668.                 &&
  669.                 (    (horizontal == requestRecPtr->reqHorizontal &&    
  670.                     vertical == requestRecPtr->reqVertical &&
  671.                     bitDepth == requestRecPtr->reqBitDepth)
  672.                     ||
  673.                     !(requestRecPtr->requestFlags & 1<<kAbsoluteRequestBit)    
  674.                 )
  675.             )
  676.         {
  677.             // go ahead and set the new values
  678.             return (true);
  679.         }
  680.         else
  681.         {
  682.             // match resolution: minimize Δh & Δv
  683.             if    (    abs((requestRecPtr->reqHorizontal - horizontal)) <=
  684.                     abs((requestRecPtr->reqHorizontal - requestRecPtr->availHorizontal)) &&
  685.                     abs((requestRecPtr->reqVertical - vertical)) <=
  686.                     abs((requestRecPtr->reqVertical - requestRecPtr->availVertical))
  687.                 )
  688.             {
  689.                 // now we have a smaller or equal delta
  690.                 //    if (h or v greater/equal to request or kMaximizeRes not set) 
  691.                 if (    (horizontal >= requestRecPtr->reqHorizontal &&
  692.                         vertical >= requestRecPtr->reqVertical)
  693.                         ||
  694.                         !(requestRecPtr->requestFlags & 1<<kMaximizeResBit)
  695.                     )
  696.                 {
  697.                     // if    (depth is equal or kBitDepthPriority not set) and
  698.                     //        (depth is less/equal or kShallowDepth not set) and
  699.                     //        ([h or v not equal] or [avail depth less reqested and new greater avail] or depth equal avail) and
  700.                     //        (request match or kAbsoluteRequest not set)
  701.                     if    (    (    requestRecPtr->availBitDepth == bitDepth ||            
  702.                                 !(requestRecPtr->requestFlags & 1<<kBitDepthPriorityBit)
  703.                             )
  704.                             &&
  705.                             (    bitDepth <= requestRecPtr->reqBitDepth ||    
  706.                                 !(requestRecPtr->requestFlags & 1<<kShallowDepthBit)        
  707.                             )
  708.                             &&
  709.                             (    (requestRecPtr->availHorizontal != horizontal ||
  710.                                 requestRecPtr->availVertical != vertical)
  711.                                 ||
  712.                                 (requestRecPtr->availBitDepth < requestRecPtr->reqBitDepth &&
  713.                                 bitDepth > requestRecPtr->availBitDepth)
  714.                                 ||
  715.                                 (bitDepth == requestRecPtr->reqBitDepth)
  716.                             )
  717.                             &&
  718.                             (    (horizontal == requestRecPtr->reqHorizontal &&    
  719.                                 vertical == requestRecPtr->reqVertical &&
  720.                                 bitDepth == requestRecPtr->reqBitDepth)
  721.                                 ||
  722.                                 !(requestRecPtr->requestFlags & 1<<kAbsoluteRequestBit)    
  723.                             )
  724.                         )
  725.                     {
  726.                         // go ahead and set the new values
  727.                         return (true);
  728.                     }
  729.                 }
  730.             }
  731.         }
  732.     }
  733.     return (false);
  734. }
  735.  
  736. void GravitateMonitors (void)
  737. {
  738.     // do the magic gravitation here
  739. }